#include "JJTState.h"
#include "python3/PythonGrammar30.h"
#include "python3/PythonTreeBuilder.h"

JJTState::JJTState():
    _sp(0),
    _mk(0),
    _nodeCreated(false),
    _debugLevel(0),
    _builder(new PythonTreeBuilder(this)),
    _grammar(NULL)
{
}

JJTState::~JJTState()
{
    delete _builder;
    _nodes.clear();
}

SimpleNodePtr JJTState::getLastOpened()
{
    return _builder->getLastOpened();
}

bool JJTState::nodeCreated()
{
    return _nodeCreated;
}

void JJTState::reset()
{
    _nodes.clear();
    _marks.clear();
    _sp = 0;
    _mk = 0;
}

SimpleNodePtr JJTState::rootNode()
{
    return _nodes.first();
}

void JJTState::pushNode(const SimpleNodePtr& n)
{

}

void JJTState::pushNode(const SimpleNodePtr& /*n*/, const SimpleNodePtr& created, int line, int col)
{
    _nodes.append(created);

    if(created->beginLine == 0)
        created->beginLine = line;

    if(created->beginColumn == 0)
        created->beginColumn = col;

    ++_sp;
}

SimpleNodePtr JJTState::popNode()
{
    if (--_sp < _mk) {
        clearMark();
    }
    if (!_nodes.isEmpty())
        return _nodes.takeLast();
    return SimpleNodePtr(NULL);
}

SimpleNodePtr JJTState::peekNode()
{
    return _nodes.length() == 0 ? SimpleNodePtr(NULL) : _nodes.last();
}

/*SimpleNodePtr JJTState::peekNode(int i)
{
    return _nodes.at(_nodes.length() - 1 - i);
}*/

int JJTState::nodeArity()
{
    return _sp - _mk;
}

void JJTState::clearNodeScope(const SimpleNodePtr& n)
{
#ifdef DEBUG
    _debugLevel -= 1;
    qDebug() <<  QString(_debugLevel*4, ' ') << _debugLevel << "clearing scope:" << n->type();
#endif

    while (_sp > _mk) {
        popNode();
    }

    _lines.takeLast();
    _columns.takeLast();

    clearMark();
}

void JJTState::openNodeScope(const SimpleNodePtr& n)
{
    TokenPtr t = _grammar->getToken(1);

#ifdef DEBUG
    qDebug() << QString(_debugLevel *4, ' ') << _debugLevel << "opening scope:"+n->type() << "tok:" << t->toString() << "line:" << t->beginLine;
    _debugLevel += 1;
#endif
    _lines.append(t->beginLine);
    _columns.append(t->beginColumn);


    _marks.append(_mk);
    _mk = _sp;
}

void JJTState::closeNodeScope(const SimpleNodePtr& n, int num)
{
#ifdef DEBUG
    _debugLevel -= 1;
    qDebug() <<  QString(_debugLevel*4, ' ') << _debugLevel << "closing scope:" << n->type();
#endif
    int line = _lines.takeLast();
    int col = _columns.takeLast();
#ifdef DEBUG
    qDebug() << " line: " << line;
#endif

    clearMark();
    SimpleNodePtr newNode = _builder->closeNode(n, num);
    if (newNode){
#ifdef DEBUG
        qDebug() << "Created node: " << newNode->toString();
#endif
        pushNode(n, newNode, line, col);
        _nodeCreated = true;
    } else {
        throw QString("Internal AST builder error");
    }

}

void JJTState::closeNodeScope(const SimpleNodePtr& n, bool condition)
{
#ifdef DEBUG
    _debugLevel -= 1;
    qDebug() <<  QString(_debugLevel*4, ' ') << _debugLevel << "closing scope:" << n->type();
#endif
    int line = _lines.takeLast();
    int col = _columns.takeLast();
#ifdef DEBUG
    qDebug() << " line: " << line;
#endif

    if (condition){
        SimpleNodePtr newNode = _builder->closeNode(n, nodeArity());
        if (newNode){
#ifdef DEBUG
            qDebug() << "Created node: " << newNode->toString();
#endif
            clearMark();
            pushNode(n, newNode, line, col);
            _nodeCreated = true;
        } else {
            throw QString("Internal AST builder error when closing node:" + n->toString());
        }
    } else {
        clearMark();
        _nodeCreated = false;
    }
}

void JJTState::clearMark()
{
    if (_marks.length() > 0) {
        _mk = _marks.takeLast();
    } else {
        _mk = 0;
    }
}

bool JJTState::lastIsNewScope()
{
    int size = _columns.length();
    if(size > 1){
        return _columns.at(size-1) <= _columns.at(size-2);
    }
    return true;
}

void JJTState::setGrammar(PythonGrammar* grammar)
{
    _grammar = grammar;
}

PythonTreeBuilder* JJTState::builder()
{
    return _builder;
}

PythonGrammar* JJTState::grammar()
{
    return _grammar;
}
